package com.qqq.commonsecurity.handler;

import com.qqq.commondomain.constants.CommonConstants;
import com.qqq.commondomain.domain.ResultCode;
import com.qqq.commondomain.domain.R;
import com.qqq.commondomain.exception.ServiceException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {


    /**
     * 设置http响应码
     *
     * @param response 响应信息
     * @param errcode  响应码
     */
    private void setResponseCode(HttpServletResponse response, Integer errcode) {
        int httpCode = Integer.parseInt(String.valueOf(errcode).substring(0, 3));
        response.setStatus(httpCode);
    }


    /**
     * 请求⽅式不⽀持
     *
     * @param e        异常信息
     * @param request  请求
     * @param response 响应
     * @return 异常结果
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R<?>
    handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,// 触发的异常对象
                                        HttpServletRequest request,// 当前HTTP请求对象
                                        HttpServletResponse// HTTP响应对象
                                                response) {
        // 获取请求路径
        String requestURI = request.getRequestURI();

        log.error("请求地址'{}',不⽀持'{}'请求", requestURI, e.getMethod());
        // 设置HTTP响应状态码
        setResponseCode(response,
                ResultCode.REQUEST_METNHOD_NOT_SUPPORTED.getCode());
        // 返回统一错误响应结构
        return R.fail(ResultCode.REQUEST_METNHOD_NOT_SUPPORTED.getCode(),
                ResultCode.REQUEST_METNHOD_NOT_SUPPORTED.getMsg());
        //这里不调用webFluxResponseWriter是因为controller层会帮忙封装返回的对象写入到http响应里
        //而网关异常处理器则需要自己写入到http响应里
    }


    /**
     * 类型不匹配异常
     *
     * @param e        异常信息
     * @param response 响应
     * @return 不匹配结果
     */
    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    public R<?>
    handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,
                                              HttpServletResponse
                                                      response) {
        log.error("类型不匹配异常", e);
        setResponseCode(response, ResultCode.PARA_TYPE_MISMATCH.getCode());
        return R.fail(ResultCode.PARA_TYPE_MISMATCH.getCode(),
                ResultCode.PARA_TYPE_MISMATCH.getMsg());
    }


    /**
     * url未找到异常
     *
     * @param e        异常信息
     * @param response 响应
     * @return 异常结果
     */
    @ExceptionHandler({NoResourceFoundException.class})
    public R<?> handleMethodNoResourceFoundException(NoResourceFoundException e,
                                                     HttpServletResponse response) {
        log.error("url未找到异常", e);
        setResponseCode(response, ResultCode.URL_NOT_FOUND.getCode());
        return R.fail(ResultCode.URL_NOT_FOUND.getCode(),
                ResultCode.URL_NOT_FOUND.getMsg());
    }


    /**
     * 业务异常
     *
     * @param e        异常信息
     * @param request  请求
     * @param response 响应
     * @return 业务异常结果
     */
    @ExceptionHandler(ServiceException.class)
    public R<?> handleServiceException(ServiceException e, HttpServletRequest request,
                                       HttpServletResponse response) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发⽣业务异常", requestURI, e);
        setResponseCode(response, e.getCode());
        return R.fail(e.getCode(), e.getMessage());
    }


    /**
     * 参数校验异常
     *
     * @param e        异常信息
     * @param request  请求
     * @param response 响应
     * @return 异常报⽂
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public R<?>
    handleMethodArgumentNotValidException(MethodArgumentNotValidException e,
                                          HttpServletRequest request,
                                          HttpServletResponse
                                                  response) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}', 发⽣参数校验异常", requestURI, e);
        setResponseCode(response, ResultCode.INVALID_PARA.getCode());
        String message = joinMessage(e);
        return R.fail(ResultCode.INVALID_PARA.getCode(), message);
    }


    /**
     * 异常消息拼接
     *
     * @param e 异常信息
     * @return 拼接好的异常信息
     */
    private String joinMessage(MethodArgumentNotValidException e) {
        List<ObjectError> allErrors = e.getAllErrors();
        if (CollectionUtils.isEmpty(allErrors)) {
            return CommonConstants.EMPTY_STR;
        }
        return allErrors.stream().map(ObjectError::getDefaultMessage)
                .collect(Collectors.joining(CommonConstants.DEFAULT_DELIMITER));
        //.stream()  // 将 List 转换为 Stream 流，便于后续操作
        //.map(ObjectError::getDefaultMessage)对流中的每个 ObjectError 对象调用 getDefaultMessage()
        //.collect(Collectors.joining(", "))  // 将流中的字符串用 ", " 拼接成一个整体字符串
    }

/**
     * 参数校验异常
     *
     * @param e        异常信息
     * @param request  请求
     * @param response 响应
     * @return 异常报⽂
     */

    @ExceptionHandler({ConstraintViolationException.class})
    public R<Void>
    handleConstraintViolationException(ConstraintViolationException e,
                                       HttpServletRequest request,
                                       HttpServletResponse
                                               response) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}', 发⽣参数校验异常", requestURI, e);
        setResponseCode(response, ResultCode.INVALID_PARA.getCode());
        String message = e.getMessage();
        return R.fail(ResultCode.INVALID_PARA.getCode(), message);
    }



    /**
     * 拦截运⾏时异常
     *
     * @param e        异常信息
     * @param request  请求信息
     * @param response 响应信息
     * @return 响应结果
     */
    @ExceptionHandler(RuntimeException.class)
    public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request,
                                       HttpServletResponse response) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发⽣运⾏时异常.", requestURI, e);
        setResponseCode(response, ResultCode.ERROR.getCode());
        return R.fail(ResultCode.ERROR.getCode(), ResultCode.ERROR.getMsg());
    }


    /**
     * 系统异常
     *
     * @param e        异常信息
     * @param request  请求
     * @param response 响应
     * @return 响应结果
     */
    @ExceptionHandler(Exception.class)
    public R<?> handleException(Exception e, HttpServletRequest request,
                                HttpServletResponse response) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发⽣异常.", requestURI, e);
        setResponseCode(response, ResultCode.ERROR.getCode());
        return R.fail(ResultCode.ERROR.getCode(), ResultCode.ERROR.getMsg());
    }


}
